using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing.Design;
using System.Collections;
using System.Web.UI.Design;

namespace Acms.WebControls
{
    [Serializable]
    [ToolboxData("<{0}:DownloadGridField runat=server></{0}:DownloadGridField>")]
    public class DownloadGridField
    {
        public DownloadGridField() : base() { }
        public DownloadGridField(string headerText, string dataField):base()
        {
            _HeaderText = headerText;
            _DataField = dataField;
        }

        public DownloadGridField(string headerText, string dataField, string format)
            : base()
        {
            _HeaderText = headerText;
            _DataField = dataField;
            _Format = format;
        }

        private string _HeaderText;
        public string HeaderText
        {
            get { return _HeaderText; }
            set { _HeaderText = value; }
        }

        private string _DataField;
        [DefaultValue("")]
        public string DataField
        {
            get { return _DataField; }
            set { _DataField = value; }
        }

        private string _Format = "";
        public string Format
        {
            get { return _Format; }
            set { _Format = value; }
        }

    }

    [ToolboxData("<{0}:DownloadingGrid runat=server></{0}:DownloadingGrid>")]
    [Designer(typeof(DownloadingGridDesigner))]
    public class DownloadingGrid : BaseDataBoundControl, IPostBackEventHandler
    {
        public DownloadingGrid()
        {
        }

        private List<DownloadGridField> _Columns = new List<DownloadGridField>();
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public List<DownloadGridField> Columns 
        { 
            get { return _Columns; }
        }

        private string fileName = "Download";
	    public string FileName
	    {
		    get { return fileName;}
		    set { fileName = value;}
	    }

        private string csvIcon;
        [Editor("System.Web.UI.Design.ImageUrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        public string CsvIcon
        {
            get { return csvIcon; }
            set { csvIcon = value; }
        }

        private string excelIcon;
        [Editor("System.Web.UI.Design.ImageUrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        public string ExcelIcon
        {
            get { return excelIcon; }
            set { excelIcon = value; }
        }

        private string xmlIcon;
        [Editor("System.Web.UI.Design.ImageUrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        public string XmlIcon
        {
            get { return xmlIcon; }
            set { xmlIcon = value; }
        }

        protected override object SaveViewState()
        {
            ViewState["FileName"] = fileName;
            ViewState["XmlIcon"] = xmlIcon;
            ViewState["CsvIcon"] = csvIcon;
            ViewState["ExcelIcon"] = excelIcon;
            List<string[]> tmp = new List<string[]>();
            foreach (DownloadGridField field in Columns)
            {
                tmp.Add(new string[] { field.DataField, field.HeaderText, field.Format });
            }
            ViewState["ColData"] = tmp;
            return base.SaveViewState();
        }

        protected override void LoadViewState(object savedState)
        {
            base.LoadViewState(savedState);
            fileName = ViewState["FileName"] as string;
            xmlIcon = ViewState["XmlIcon"] as string;
            csvIcon = ViewState["CsvIcon"] as string;
            excelIcon = ViewState["ExcelIcon"] as string;

            List<string[]> tmp = ViewState["ColData"] as List<string[]>;
            if(tmp != null)
            {
                int i = 0;
                foreach (DownloadGridField field in Columns)
                {
                    if(tmp.Count> i && tmp[i] != null)
                    {
                        field.DataField = tmp[i][0];
                        field.HeaderText = tmp[i][1];
                        field.Format = tmp[i][2];
                    }
                    i++;
                }
            }
        }

        public override void DataBind()
        {
        }

        protected override void Render(HtmlTextWriter writer)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Class, "downloadList");
            writer.RenderBeginTag(HtmlTextWriterTag.Div);

            writer.RenderBeginTag(HtmlTextWriterTag.Label);
            writer.Write("Download as :");
            writer.RenderEndTag();

            writer.RenderBeginTag(HtmlTextWriterTag.Ul);

            RenderDownloadLink(writer, DonwloadAs.Excel, "Excel Xml", ExcelIcon);
            RenderDownloadLink(writer, DonwloadAs.Csv, "CSV", CsvIcon);
            RenderDownloadLink(writer, DonwloadAs.Xml, "Xml", XmlIcon);

            writer.RenderEndTag();//ul
            writer.RenderEndTag();//div
        }

        private void RenderDownloadLink(HtmlTextWriter writer, DonwloadAs key, string fileDescription, string iconPath)
        {
            writer.RenderBeginTag(HtmlTextWriterTag.Li);
            writer.AddAttribute(HtmlTextWriterAttribute.Href, Page.ClientScript.GetPostBackClientHyperlink(this, string.Format("Download_{0}", key.ToString()), false));
            writer.RenderBeginTag(HtmlTextWriterTag.A);
            if (string.IsNullOrEmpty(iconPath))
            {
                writer.Write("{0} file.", fileDescription);
            }
            else
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Alt, string.Format("Download as {0} file.", fileDescription));
                writer.AddAttribute(HtmlTextWriterAttribute.Src, Page.ResolveUrl(iconPath));
                writer.RenderBeginTag(HtmlTextWriterTag.Img);
                writer.RenderEndTag();
            }
            writer.RenderEndTag();
            writer.RenderEndTag();
        }

        #region IPostBackEventHandler Members

        public void RaisePostBackEvent(string eventArgument)
        {
            if (eventArgument != null && eventArgument.StartsWith("Download_"))
            {
                string key = eventArgument.Substring(9);
                try
                {
                    currentDownload = (DonwloadAs)Enum.Parse(typeof(DonwloadAs), key);
                }
                catch
                {
                    throw;
                }
                PerformSelect();
            }
        }


        #endregion

        private bool addAttachmentHeader = true;
        public enum DonwloadAs
        {
            Csv,
            Excel,
            Xml
        }
        private DonwloadAs currentDownload = DonwloadAs.Csv;

        private void SetResponseHeaders(string fileType, string contentType)
        {
            Page.Response.ClearHeaders();
            Page.Response.Clear();
            Page.Response.ContentType = contentType;
            if (addAttachmentHeader)
            {
                Page.Response.AppendHeader("Content-Disposition", string.Format("attachment;filename={0}_{1:yyyy_MM_dd_hh_mm_ss}.{2}", FileName, DateTime.Now, fileType));
            }
        }

        private void RenderXmlDownload(IEnumerable data)
        {
            SetResponseHeaders("xml", "text/xml");
            System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(Page.Response.OutputStream, System.Text.UTF8Encoding.UTF8);
            writer.Formatting = System.Xml.Formatting.Indented;
            writer.WriteStartDocument();

            writer.WriteStartElement(FileName.Replace(" ", "_").ToLower());

            IEnumerator enumerator = data.GetEnumerator();
            while (enumerator.MoveNext())
            {
                writer.WriteStartElement("item");
                foreach (DownloadGridField column in this.Columns)
                {
                    writer.WriteStartElement(column.HeaderText.Replace(" ","_").ToLower());
                    object val = DataBinder.Eval(enumerator.Current, column.DataField);
                    if (val != null)
                    {
                        if(string.IsNullOrEmpty(column.Format))
                        {
                            writer.WriteString(val.ToString());
                        }
                        else
                        {
                            writer.WriteString(string.Format(column.Format, val));
                        }
                    }
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
            }
            writer.WriteEndElement();
            writer.WriteEndDocument();
            writer.Close();
            Page.Response.Flush();
            Page.Response.End();

        }

        private void RenderXlsDownload(IEnumerable data)
        {
            CarlosAg.ExcelXmlWriter.Workbook xls = new CarlosAg.ExcelXmlWriter.Workbook();
            xls.Worksheets.Add(FileName);
            xls.Worksheets[0].Table.Rows.Add();
            foreach (DownloadGridField column in this.Columns)
            {
                xls.Worksheets[0].Table.Rows[0].Cells.Add(column.HeaderText);
            }

            IEnumerator enumerator = data.GetEnumerator();
            while (enumerator.MoveNext())
            {
                CarlosAg.ExcelXmlWriter.WorksheetRow row = xls.Worksheets[0].Table.Rows.Add() ;
                foreach (DownloadGridField column in this.Columns)
                {
                    object actual = DataBinder.Eval(enumerator.Current, column.DataField);
                    string val = null;
                    if (actual != null && !string.IsNullOrEmpty(column.Format))
                    {
                        val = string.Format(column.Format, actual);
                    }
                    else if(actual != null)
                    {
                        val = actual.ToString();
                    }

                    CarlosAg.ExcelXmlWriter.WorksheetCell cell = row.Cells.Add(val);
                    
                    if(actual != null)
                    {
                        /*if (actual is DateTime)
                        {
                            cell.Data.Type = CarlosAg.ExcelXmlWriter.DataType.DateTime;
                        }
                        else if (actual is bool)
                        {
                            cell.Data.Type = CarlosAg.ExcelXmlWriter.DataType.Boolean;
                        }
                        else if (actual is int || actual is short || actual is long || actual is decimal || actual is double || actual is float || actual is uint || actual is ulong || actual is ushort)
                        {
                            cell.Data.Type = CarlosAg.ExcelXmlWriter.DataType.Number;
                        }
                        else 
                        {
                            cell.Data.Type = CarlosAg.ExcelXmlWriter.DataType.String;

                        }*/
                    }
                }
            }

            SetResponseHeaders("xml", "text/xml");
            xls.Save(Page.Response.OutputStream);
            Page.Response.End();
        }

        private void RenderCsvDownload(IEnumerable data)
        {
            SetResponseHeaders("csv", "text/csv");
            System.IO.StreamWriter writer = new System.IO.StreamWriter(Page.Response.OutputStream);

            string spacer = "";
            foreach (DownloadGridField column in this.Columns)
            {
                writer.Write(string.Concat(spacer, "\"", column.HeaderText, "\""));
                spacer = ",";
            }
            writer.Write(writer.NewLine);

            IEnumerator enumerator = data.GetEnumerator();
            while (enumerator.MoveNext())
            {
                spacer = "";
                foreach (DownloadGridField column in this.Columns)
                {
                    object val = null;
                    if (!string.IsNullOrEmpty(column.DataField) && !string.IsNullOrEmpty(column.Format))
                    {
                        val = DataBinder.Eval(enumerator.Current, column.DataField, column.Format);
                    }
                    else if (!string.IsNullOrEmpty(column.DataField))
                    {
                        val = DataBinder.Eval(enumerator.Current, column.DataField);
                    }

                    writer.Write(string.Concat(spacer, "\"", val, "\""));
                    spacer = ",";
                }
                writer.Write(writer.NewLine);
            }
            writer.Close();

            Page.Response.End();
        }

        private void RenderDownload(IEnumerable data)
        {
            if (currentDownload == DonwloadAs.Csv)
            {
                RenderCsvDownload(data);
            }
            else if (currentDownload == DonwloadAs.Excel)
            {
                RenderXlsDownload(data);
            }
            else if (currentDownload == DonwloadAs.Xml)
            {
                RenderXmlDownload(data);
            }
        }



        protected override void PerformSelect()
        {
            if (!IsBoundUsingDataSourceID)
            {
                OnDataBinding(EventArgs.Empty);
                RenderDownload(this.DataSource as IEnumerable);
                return;
            }

            // The GetData method retrieves the DataSourceView object from  
            // the IDataSource associated with the data-bound control.            
            IDataSource ds = GetDataSource();
            if(ds != null)
            {
                DataSourceView dv = ds.GetView("default");
                if(dv != null)
                {
                    dv.Select(CreateDataSourceSelectArguments(), OnDataSourceViewSelectCallback);
                }
            }

            // The PerformDataBinding method has completed.
            RequiresDataBinding = false;
        }

        
        private DataSourceSelectArguments CreateDataSourceSelectArguments()
        {
            DataSourceSelectArguments tmp = new DataSourceSelectArguments();
            return tmp;
        }

        private void OnDataSourceViewSelectCallback(IEnumerable retrievedData)
        {

            // Call OnDataBinding only if it has not already been 
            // called in the PerformSelect method.
            if (IsBoundUsingDataSourceID)
            {
                OnDataBinding(EventArgs.Empty);
            }
            // The PerformDataBinding method binds the data in the  
            // retrievedData collection to elements of the data-bound control.
            RenderDownload(retrievedData);
        }

        protected IDataSource GetDataSource()
        {
            return this.NamingContainer.FindControl(DataSourceID) as IDataSource;
        }

        protected override void ValidateDataSource(object dataSource)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }

    internal class DownloadingGridDesigner : ControlDesigner
    {
        public override void Initialize(IComponent component)
        {
            if (component is DownloadingGrid)
            {
                base.Initialize(component);
                grid = (DownloadingGrid)component;
            }
        }

        protected DownloadingGrid grid;

        public override string GetDesignTimeHtml()
        {
            try
            {
                // Start building the HTML
                StringBuilder sb = new StringBuilder();
                System.IO.StringWriter sw = new System.IO.StringWriter(sb);
                HtmlTextWriter writer = new HtmlTextWriter(sw);

                writer.AddAttribute(HtmlTextWriterAttribute.Class, "downloadList");
                writer.RenderBeginTag(HtmlTextWriterTag.Div);

                writer.RenderBeginTag(HtmlTextWriterTag.Label);
                writer.Write("Download as :");
                writer.RenderEndTag();

                writer.RenderBeginTag(HtmlTextWriterTag.Ul);

                RenderDownloadLink(writer, DownloadingGrid.DonwloadAs.Excel, "Excel Xml", grid.ExcelIcon);
                RenderDownloadLink(writer, DownloadingGrid.DonwloadAs.Csv, "CSV", grid.CsvIcon);
                RenderDownloadLink(writer, DownloadingGrid.DonwloadAs.Xml, "Xml", grid.XmlIcon);

                writer.RenderEndTag();//ul
                writer.RenderEndTag();//div

                if (grid.Columns.Count > 0)
                {

                    writer.RenderBeginTag(HtmlTextWriterTag.Table);
                    writer.RenderBeginTag(HtmlTextWriterTag.Tr);

                    foreach (DownloadGridField field in grid.Columns)
                    {
                        writer.RenderBeginTag(HtmlTextWriterTag.Th);
                        writer.Write(field.HeaderText);
                        writer.RenderEndTag();//th
                    }

                    writer.RenderEndTag();//tr

                    writer.RenderBeginTag(HtmlTextWriterTag.Tr);
                    foreach (DownloadGridField field in grid.Columns)
                    {
                        writer.RenderBeginTag(HtmlTextWriterTag.Td);
                        writer.Write(field.DataField);
                        writer.RenderEndTag();//th
                    }

                    writer.RenderEndTag();//tr
                    writer.RenderEndTag();//table
                }
                else
                {
                    writer.RenderBeginTag(HtmlTextWriterTag.Span);
                    writer.Write("No data columns");
                    writer.RenderEndTag();
                }
                return sb.ToString();

            }

            catch (Exception ex)
            {

                // Display the error in VS.net, in Design view

                return String.Concat("<h3>Error</h3>Stack Trace:<br>", ex.StackTrace);

            }
        }

        private void RenderDownloadLink(HtmlTextWriter writer, DownloadingGrid.DonwloadAs donwloadAs, string fileDescription, string iconPath)
        {
            writer.RenderBeginTag(HtmlTextWriterTag.Li);
            writer.RenderBeginTag(HtmlTextWriterTag.A);
            if (string.IsNullOrEmpty(iconPath))
            {
                writer.Write("{0} file.", fileDescription);
            }
            else
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Alt, string.Format("Download as {0} file.", fileDescription));
                writer.AddAttribute(HtmlTextWriterAttribute.Src, base.ViewControl.ResolveUrl(iconPath));
                writer.RenderBeginTag(HtmlTextWriterTag.Img);
                writer.RenderEndTag();
            }
            writer.RenderEndTag();
            writer.RenderEndTag();
        }

        
    }
}
